#include <stdio.h>      // 标准输入输出
#include "ohos_init.h"  // 用于初始化服务(services)和功能(features)
#include "cmsis_os2.h"  // CMSIS-RTOS API V2

#include "hi_io.h"
#include "hi_gpio.h"

#include "MQTTClient.h" //mqtt三方库
#include "cJSON.h"      //cJson解析三方库
// #include "wifi_device.h"    // Wi-Fi设备接口：station模式
#include "wifi_connecter.h" // easy wifi (station模式)
#include "iot_watchdog.h" 

#define LED_GPIO HI_IO_NAME_GPIO_7
#define KEY_GPIO HI_IO_NAME_GPIO_5


// 定义一个宏，用于标识SSID。请根据实际情况修改
#define PARAM_HOTSPOT_SSID "w"

// 定义一个宏，用于标识密码。请根据实际情况修改
#define PARAM_HOTSPOT_PSK "12345678"

// 定义一个宏，用于标识加密方式
#define PARAM_HOTSPOT_TYPE WIFI_SEC_TYPE_PSK

// 定义一个宏，用于标识MQTT服务器IP地址。请根据实际情况修改
#define HOST_ADDR "59e62b5755.st1.iotda-device.cn-north-4.myhuaweicloud.com"

// 定义一个宏，用于标识MQTT服务器端口
#define HOST_PORT 1883

// 定义一个宏，用于标识智能家居的设备ID
#define DEVICE_ID "67eb96a85367f573f77e8956_led_light_test"
// 定义一个宏，用于标识用于MQTT连接的clientid
#define MQTT_CLIENT_ID "67eb96a85367f573f77e8956_led_light_test_0_0_2025041802"

// 定义一个宏，用于标识用于MQTT连接的username
#define MQTT_USERNAME "67eb96a85367f573f77e8956_led_light_test"

// 定义一个宏，用于标识用于MQTT连接的password
#define MQTT_PASSWORD "40aef8188d0e3567232a01cf075a20b52bbf14a2e95a84642e9eaff4826718bb"



// 定义一个宏，用于标识设备属性上报所用的topic
#define PUBLISH_TOPIC "$oc/devices/"DEVICE_ID"/sys/properties/report"
// 定义一个宏，用于标识订阅下发命令所用的topic
#define SUBCRIB_TOPIC "$oc/devices/"DEVICE_ID"/sys/commands/#" 
// 定义一个宏，用于标识执行完成下发命令所返回响应的topic
#define RESPONSE_TOPIC "$oc/devices/"DEVICE_ID"/sys/commands/response" 

//定义用于mqtt连接的两个对象变量，对象类型来自mqtt三方库
Network network;    
MQTTClient client;

static unsigned char sendBuf[1000];
static unsigned char readBuf[1000];

static osMutexId_t wifi_mutex;

static void init_mutex(void)
{
    if(wifi_mutex == NULL){
        wifi_mutex = osMutexNew(NULL);
    }
}

static void PrintLinkedInfo(WifiLinkedInfo* info)
{
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}

static volatile int g_connected = 0;

static void OnWifiConnectionChanged(int state, WifiLinkedInfo* info)
{
    if (!info) return;

    printf("%s %d, state = %d, info = \r\n", __FUNCTION__, __LINE__, state);
    PrintLinkedInfo(info);

    if (state == WIFI_STATE_AVAILABLE) {
        g_connected = 1;
    } else {
        g_connected = 0;
    }
}

static void OnWifiScanStateChanged(int state, int size)
{
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);
}

static int init_wifi_once(void)
{   
    static int initialized = 0;
    int result = WIFI_SUCCESS;
    if(wifi_mutex == NULL) init_mutex();

    if(osMutexAcquire(wifi_mutex,osWaitForever) != osOK){
        printf("Failed to acquire wifi_mutext\n");
        return -1;
    }

    if(!initialized){
        if(EnableWifi() != WIFI_SUCCESS){
            printf("EnableWifi failed\n");
            result = -1;
            goto exit;
        }
    
        osDelay(100);
        static WifiEvent g_defaultWifiEventListener = {
            .OnWifiConnectionChanged = OnWifiConnectionChanged,
            .OnWifiScanStateChanged = OnWifiScanStateChanged
        };
        if(RegisterWifiEvent(&g_defaultWifiEventListener) != WIFI_SUCCESS){
            printf("RegisterWifiEvent failed \n");
            result = -1;
            goto exit;
        }
    
        initialized = 1;
    }
exit:
    osMutexRelease(wifi_mutex);
    
    return WIFI_SUCCESS;
}

static int connect_to_wifi(void)
{
    // 连接AP
    // 定义热点配置
    WifiDeviceConfig config = {0};
    // 设置热点配置中的SSID
    strcpy(config.ssid, PARAM_HOTSPOT_SSID);
    // 设置热点配置中的密码
    strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
    // 设置热点配置中的加密方式
    config.securityType = PARAM_HOTSPOT_TYPE;
    // 等待100ms
    osDelay(100);

    // 连接到热点
    int netId = ConnectToHotspot(&config);
    // 检查是否成功连接到热点
    if (netId < 0)
    {
        printf("Connect to AP failed!\r\n");
        return;
    }
    printf("wifi connect successful !\n");
    return 0;
}

static void mqtt_connect_retry(void)
{
// 初始化并启动MQTT任务，连接MQTT服务器
int rc = 0;
begin:   
    //初始化NetworkInit
    NetworkInit(&network);
    // 连接网络
    NetworkConnect(&network, HOST_ADDR, HOST_PORT);

    printf("MQTTClientInit  ...\n");

    MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = MQTT_CLIENT_ID;
    MQTTString userName = MQTTString_initializer;
    userName.cstring = MQTT_USERNAME;
    MQTTString password = MQTTString_initializer;
    password.cstring = MQTT_PASSWORD;
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID = clientId;
    data.username = userName;
	data.password = password;
    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;
    printf("MQTTConnect  ...\n");
    
    rc = MQTTConnect(&client, &data);
    if (rc != 0) {
        printf("MQTTConnect: %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        goto begin;
    }else{
        printf("MQTTConnect successful \n");
    }
}

static void mqtt_init(void)
{
    printf(">>>>>>>>>> MQTT Init Starting ...\n");
    init_mutex();

    if(init_wifi_once() != WIFI_SUCCESS) return;
    if(connect_to_wifi() != 0) return;

    mqtt_connect_retry();
}

// mqtt发送
void mqtt_publish(hi_gpio_value led_val)
{
    MQTTMessage message;
    char payload[500]={0};
    
    //--将读取到的AHT20传感器数据封装成上华为云iot平台的数据结构--start
    cJSON *root = cJSON_CreateObject(); // 创建JSON对象

    if (root != NULL) {
        // 创建数组，用于存放服务数据
        cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");

        // 创建数组项，代表单个服务
        cJSON *arr_item = cJSON_CreateObject();

        // 添加服务ID
        cJSON_AddStringToObject(arr_item, "service_id", "service_iot_led");

        // 创建对象，用于存放属性
        cJSON *pro_obj = cJSON_CreateObject();
        cJSON_AddItemToObject(arr_item, "properties", pro_obj);

        // 添加温度和湿度数据到属性对象
        if(led_val == HI_GPIO_VALUE1){
            cJSON_AddStringToObject(pro_obj, "light", "OFF");
        }else{
            cJSON_AddStringToObject(pro_obj, "light", "ON");
        }

        // 将服务数组项添加到服务数组中
        cJSON_AddItemToArray(serv_arr, arr_item);

        // 将JSON对象转换为字符串
        char *payload_str = cJSON_PrintUnformatted(root);
        if (payload_str != NULL) {
            strcpy(payload, payload_str); // 将JSON字符串复制到payload
            cJSON_free(payload_str); // 释放cJSON分配的内存
        }

        // 删除JSON对象，释放内存
        cJSON_Delete(root);
    }
    
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    
    message.payloadlen = strlen(payload);

    int rc = 0;

    if ((rc = MQTTPublish(&client, PUBLISH_TOPIC, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        mqtt_init();
    }else{
        printf("mqtt publish success:%s\n",payload);
    }
}

// 安装中断处理函数
void keyPressedFunc(void *arg)
{
    /*
        静态局部变量：
        使用 static 声明的局部变量在程序运行期间一直存在（即它的生命周期是整个程序运行期间），但它仍然只能在声明它的函数内部访问（即作用域不变）。
        此外，静态局部变量只会被初始化一次，之后的函数调用会保留上次的值。
    */ 
    static hi_gpio_value led_val = HI_GPIO_VALUE0;
    (void)arg;
    printf("key pressed \n");
    printf("led_val %d \n",led_val);
    // 设置LED的电平
    hi_gpio_set_ouput_val(LED_GPIO,led_val);
    mqtt_publish(led_val);
    led_val = !led_val;
    return ;
}

// 消息到达的回调函数
void messageArrived(MessageData* data) {
    printf("===>> messageArrived start  \n");
    int rc;
    printf("Message arrived on topic %d %.*s: %.*s\n", data->message->qos,data->topicName->lenstring.len, data->topicName->lenstring.data,
           data->message->payloadlen, data->message->payload);

    /*
        /xx//x/x//x/requets_id=123456
    */

   //get request id
    char *request_id_idx=NULL;
    char *request_id[36]={0};
    request_id_idx = strstr(data->topicName->lenstring.data,"request_id=");
    printf("data->topicName->lenstring.data:%s\n",data->topicName->lenstring.data);
    strncpy(request_id,request_id_idx+11,36);
    printf("request_id=%s======================\n",request_id);

    //create response topic
    char rsptopic[128]= {0};
    printf("request_id=%s======================\n",request_id);
    printf("RESPONSE_TOPIC=%s======================\n",RESPONSE_TOPIC);
    sprintf(rsptopic,"%s/request_id=%s",RESPONSE_TOPIC,request_id);
    printf("rsptopic=%s=========================\n",rsptopic);
    printf("msg=%s\n",data->message->payload);

    //response message
    MQTTMessage message;
    char payload[300];
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    sprintf(payload, "{ \
    \"result_code\": 0, \
    \"response_name\": \"COMMAND_RESPONSE\", \
    \"paras\": { \
        \"result\": \"success\" \
    } \
    }" );
    message.payloadlen = strlen(payload);
    printf("mqtt publish success:%s\n",message.payload);
    //publish the msg to responese topic
    if ((rc = MQTTPublish(&client, rsptopic, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        
    }
    // 解析JSON数据
    cJSON *root = cJSON_ParseWithLength((char *)data->message->payload, data->message->payloadlen);
    if (root == NULL) {
        printf("Error parsing JSON\n");
        return;
    }

    // 获取命令名称
    cJSON *cmd_name = cJSON_GetObjectItem(root, "command_name");
     if (cmd_name == NULL) {
        cJSON_Delete(root);
    }

    if (strcmp(cJSON_GetStringValue(cmd_name), "light_toggle") == 0) {
         cJSON *paras =cJSON_GetObjectItem(root, "paras");
        if (paras == NULL) {
            cJSON_Delete(root);
        }
        cJSON *para = cJSON_GetObjectItem(paras, "light_status");
        if (para == NULL) {
            cJSON_Delete(root);
        }
        if (strcmp(cJSON_GetStringValue(para), "ON") == 0) {//数据类型：string

            keyPressedFunc(NULL);
            printf("light ON successful!\n");
        } 
        if (strcmp(cJSON_GetStringValue(para), "OFF") == 0) {//数据类型：string

            keyPressedFunc(NULL);
            printf("light OFF successful!\n");
        } 
       
    } else {
        printf("Unknown command or missing command_name\n");
    }

    // 清理JSON
    cJSON_Delete(root);
}

void mqtt_subscribe()
{
    printf("MQTTSubscribe  ...\n");
    int rc = 0;
    rc = MQTTSubscribe(&client, SUBCRIB_TOPIC, 0, messageArrived);
    if (rc != 0) {
        printf("MQTTSubscribe: %d\n", rc);
        osDelay(200);
        mqtt_init();
    }else{
        printf("MQTTSubscribe successful \n");
    }

    // while(1){
    //     MQTTYield(&client, 5000);
    // }
}

void led_init(void)
{
    // 初始化GPIO
    // hi_io.h 包中的接口
    hi_gpio_init();

    // 设置gpio下拉模式 (默认低电平灭)
    hi_io_set_pull(LED_GPIO,HI_IO_PULL_NONE);

    // 设置io引脚为通用IO (因为芯片引脚少 功能多 所以先设置该引脚是干什么作用的)
    hi_io_set_func(LED_GPIO,HI_IO_FUNC_GPIO_7_GPIO);

    // 设置GPIO为输出
    hi_gpio_set_dir(LED_GPIO,HI_GPIO_DIR_OUT);
    hi_gpio_set_ouput_val(LED_GPIO,HI_GPIO_VALUE1);
    return ;
}

void key_init(void)
{
    // 初始化GPIO
    hi_gpio_init();

    // 设置io引脚为通用IO (因为芯片引脚少 功能多 所以先设置该引脚是干什么作用的)
    hi_io_set_func(KEY_GPIO,HI_IO_FUNC_GPIO_5_GPIO);

    // 设置gpio上拉（默认高电平）
    // hi_io_set_pull(KEY_GPIO,HI_IO_PULL_UP);

    // 设置GPIO为输入
    hi_gpio_set_dir(KEY_GPIO,HI_GPIO_DIR_IN);

    // 注册GPIO中断处理函数
    hi_gpio_register_isr_function(KEY_GPIO,   /* GPIO引脚 */
        HI_INT_TYPE_EDGE,                     /* 边沿触发 */
        HI_GPIO_EDGE_FALL_LEVEL_LOW,          /* 下降沿触发 */
        keyPressedFunc,                       /* 中断处理函数 */
        NULL
    );

    return;
}

static void mqtt_led_task(void)
{
    mqtt_init();
    led_init();
    key_init();
    mqtt_subscribe();
    while(1){
        MQTTYield(&client, 5000);
    }
    // printf("20000000000000000 WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW \n");
}

static void led_switch(void)
{
    IoTWatchDogDisable();
    osThreadAttr_t attr;               // 定义一个线程属性

    attr.name = "LedTask";             // 设置任务名
    attr.stack_size = 10240;            // 设置线程任务栈空间大小
    attr.priority = osPriorityNormal;  // 设置线程优先级

    // 创建线程（到内核API详述）
    // 1.0 CMSIS-RTOS2 API：third_party\cmsis\CMSIS\RTOS2\Include\cmsis_os2.h
    // 1.1.3 kernel\liteos_m\kal\cmsis\cmsis_liteos2.c
    // RTOS: real-time operating system
    // CMSIS: Cortex Microcontroller Software Interface Standard
    if (osThreadNew((osThreadFunc_t)mqtt_led_task, NULL, &attr) == NULL)
    {
        printf("[led_switch] Create mqtt_led_task failed!\n");
    }
}

// ohos_init.h 中定义的宏，让函数在系统启动时执行
// SYS_RUN(led_switch);
APP_FEATURE_INIT(led_switch);
